import random
import time

import pytest
import requests
import json
from unittest.mock import patch, MagicMock
from itertools import product

# 配置信息
API_URL = "https://cvm.tencentcloudapi.com/"
REGION = "ap-guangzhou"
SECRET_ID = "your-secret-id"
SECRET_KEY = "your-secret-key"


def generate_signature(params, SECRET_KEY):
    """生成签名（模拟实现）"""
    return "mock-signature"


def send_request(action, params=None):
    """发送API请求（模拟实现）"""
    if params is None:
        params = {}
    common_params = {
        "Action": action,
        "Version": "2017-03-12",
        "Region": REGION,
        "SecretId": SECRET_ID,
        "Timestamp": int(time.time()),
        "Nonce": random.randint(1, 1000000),
        "SignatureMethod": "HmacSHA256"
    }
    all_params = {**common_params, **params}
    all_params["Signature"] = generate_signature(all_params, SECRET_KEY)

    response = requests.post(API_URL, data=all_params)
    return response.json()


# 定义所有错误码及其测试参数
ERROR_CODE_CASES = [
    # FailedOperation 系列
    ("FailedOperation.InvalidInstanceApplicationRole", {"InstanceId": "ins-app-role"}),
    ("FailedOperation.InvalidInstanceApplicationRoleEmr", {"InstanceId": "ins-emr"}),
    ("FailedOperation.PromotionalPerioRestriction", {"InstanceId": "ins-promotional"}),

    # InternalError 系列
    ("InternalError.TradeUnknownError", {"InstanceId": "ins-trade"}),
    ("InternalServerError", {"InstanceId": "ins-server"}),

    # InvalidAccount 系列
    ("InvalidAccount.InsufficientBalance", {"InstanceId": "ins-low-balance"}),
    ("InvalidAccount.UnpaidOrder", {"InstanceId": "ins-unpaid"}),

    # InvalidHostId 系列
    ("InvalidHostId.Malformed", {"InstanceId": "ins-123456", "HostId": "host-123"}),  # 无效CDH ID

    # InvalidInstance 系列
    ("InvalidInstance.NotSupported", {"InstanceId": "ins-unsupported"}),

    # InvalidInstanceId 系列
    ("InvalidInstanceId.Malformed", {"InstanceId": "ins-123"}),  # 短实例ID
    ("InvalidInstanceId.NotFound", {"InstanceId": "ins-missing"}),

    # InvalidInstanceType 系列
    ("InvalidInstanceType.Malformed", {"InstanceId": "ins-123456", "InstanceType": "invalid"}),

    # InvalidParameter 系列
    ("InvalidParameter", {"InvalidParam": "error"}),  # 通用参数错误
    ("InvalidParameter.HostIdCustomizedInstanceTypeNotSupport",
     {"InstanceId": "ins-cdh", "HostId": "host-cdh", "InstanceType": "custom"}),
    ("InvalidParameter.HostIdInstanceTypeNotSupport",
     {"InstanceId": "ins-cdh", "HostId": "host-cdh", "InstanceType": "unsupported"}),
    ("InvalidParameter.HostIdStandardInstanceTypeNotSupport",
     {"InstanceId": "ins-cdh", "HostId": "host-cdh", "InstanceType": "standard"}),
    ("InvalidParameter.HostIdStatusNotSupport", {"InstanceId": "ins-cdh", "HostId": "host-busy"}),
    ("InvalidParameter.InstanceTypeSupportedHostNotFound", {"InstanceId": "ins-cdh", "InstanceType": "rare-type"}),

    # InvalidParameterValue 系列
    ("InvalidParameterValue", {"Parameter": "invalid-value"}),  # 通用参数取值错误
    ("InvalidParameterValue.BasicNetworkInstanceFamily", {"InstanceId": "ins-basic-net"}),
    ("InvalidParameterValue.GPUInstanceFamily", {"InstanceId": "ins-non-gpu", "InstanceType": "gpu-type"}),
    ("InvalidParameterValue.InstanceIdMalformed", {"InstanceId": "INS-123456"}),  # 大写字母实例ID
    ("InvalidParameterValue.InvalidAppIdFormat", {"InstanceId": "ins-123456", "AppId": "invalid-app"}),
    ("InvalidParameterValue.InvalidGPUFamilyChange", {"InstanceId": "ins-gpu", "InstanceType": "non-gpu"}),
    ("InvalidParameterValue.InvalidInstanceSource", {"InstanceId": "ins-free"}),
    ("InvalidParameterValue.LimitExceeded", {"InstanceId": "ins-123456", "DataDisks": [{}] * 101}),  # 假设最多100个
    ("InvalidParameterValue.ZoneNotSupported", {"InstanceId": "ins-123456", "Zone": "invalid-zone"}),

    # InvalidPeriod 系列
    ("InvalidPeriod", {"InstanceId": "ins-123456", "Period": 13}),  # 无效时长

    # InvalidPermission 系列
    ("InvalidPermission", {"InstanceId": "ins-no-perm"}),

    # InvalidZone 系列
    ("InvalidZone.MismatchRegion", {"InstanceId": "ins-123456", "Zone": "ap-mars"}),

    # LimitExceeded 系列
    ("LimitExceeded.EipNumLimit", {"InstanceId": "ins-eip-limit"}),
    ("LimitExceeded.EniLimitInstanceType", {"InstanceId": "ins-eni-limit"}),
    ("LimitExceeded.EniNumLimit", {"InstanceId": "ins-eni-num-limit"}),
    ("LimitExceeded.InstanceTypeBandwidth", {"InstanceId": "ins-bandwidth-limit", "InternetMaxBandwidthOut": 1000}),
    ("LimitExceeded.SpotQuota", {"InstanceId": "ins-spot", "InstanceChargeType": "SPOTPAID"}),

    # MissingParameter 系列
    ("MissingParameter", {}),  # 无参数

    # OperationDenied 系列
    ("OperationDenied.InstanceOperationInProgress", {"InstanceId": "ins-in-progress"}),

    # ResourceInsufficient 系列
    ("ResourceInsufficient.CloudDiskSoldOut",
     {"InstanceId": "ins-disk-sold", "SystemDisk": {"DiskType": "CLOUD_PREMIUM", "DiskSize": 500}}),
    ("ResourceInsufficient.CloudDiskUnavailable",
     {"InstanceId": "ins-disk-invalid", "SystemDisk": {"DiskType": "INVALID"}}),
    ("ResourceInsufficient.SpecifiedInstanceType", {"InstanceId": "ins-type-out", "InstanceType": "hot-type"}),

    # ResourceNotFound 系列
    ("ResourceNotFound.InvalidZoneInstanceType",
     {"InstanceId": "ins-zone-type", "Zone": "ap-guangzhou", "InstanceType": "unsupported"}),

    # ResourceUnavailable 系列
    ("ResourceUnavailable.InstanceType",
     {"InstanceId": "ins-zone-unsell", "Zone": "ap-guangzhou", "InstanceType": "special-type"}),

    # ResourcesSoldOut 系列
    ("ResourcesSoldOut.AvailableZone", {"InstanceId": "ins-zone-sold", "Zone": "sold-out-zone"}),
    ("ResourcesSoldOut.SpecifiedInstanceType", {"InstanceId": "ins-type-sold", "InstanceType": "sold-out-type"}),

    # UnauthorizedOperation 系列
    ("UnauthorizedOperation.MFAExpired", {"InstanceId": "ins-mfa-expired"}),
    ("UnauthorizedOperation.MFANotFound", {"InstanceId": "ins-mfa-missing"}),

    # UnsupportedOperation 系列（实例状态相关）
    ("UnsupportedOperation.DiskSnapCreateTimeTooOld", {"InstanceId": "ins-snap-recent"}),
    ("UnsupportedOperation.HeterogeneousChangeInstanceFamily",
     {"InstanceId": "ins-heterogeneous", "InstanceType": "different-family"}),
    ("UnsupportedOperation.InstanceMixedResetInstanceType", {"InstanceId": "ins-mixed", "InstanceType": "mix-type"}),
    ("UnsupportedOperation.InstanceReinstallFailed", {"InstanceId": "ins-reinstall-failed"}),
    ("UnsupportedOperation.InstanceStateBanning", {"InstanceId": "ins-banned"}),
    ("UnsupportedOperation.InstanceStateExitServiceLiveMigrate", {"InstanceId": "ins-exit-migrate"}),
    ("UnsupportedOperation.InstanceStateFreezing", {"InstanceId": "ins-frozen"}),
    ("UnsupportedOperation.InstanceStateRebooting", {"InstanceId": "ins-rebooting"}),
    ("UnsupportedOperation.InstanceStateRescueMode", {"InstanceId": "ins-rescue"}),
    ("UnsupportedOperation.InstanceStateRunning", {"InstanceId": "ins-running"}),
    ("UnsupportedOperation.InstanceStateShutdown", {"InstanceId": "ins-shutdown"}),
    ("UnsupportedOperation.InstanceStateStarting", {"InstanceId": "ins-starting"}),
    ("UnsupportedOperation.InstanceStateStopping", {"InstanceId": "ins-stopping"}),
    ("UnsupportedOperation.InstanceStateTerminating", {"InstanceId": "ins-terminating"}),

    # UnsupportedOperation 系列（特殊配置）
    ("UnsupportedOperation.InvalidInstanceWithSwapDisk", {"InstanceId": "ins-swap"}),
    ("UnsupportedOperation.LocalDataDiskChangeInstanceFamily", {"InstanceId": "ins-local-disk"}),
    ("UnsupportedOperation.LocalDiskMigratingToCloudDisk", {"InstanceId": "ins-migrating-disk"}),
    (
    "UnsupportedOperation.NoInstanceTypeSupportSpot", {"InstanceId": "ins-standard", "InstanceChargeType": "SPOTPAID"}),
    ("UnsupportedOperation.NotSupportUnpaidOrder", {"InstanceId": "ins-unpaid-order"}),
    ("UnsupportedOperation.OriginalInstanceTypeInvalid", {"InstanceId": "ins-invalid-original"}),
    ("UnsupportedOperation.RedHatInstanceUnsupported", {"InstanceId": "ins-redhat"}),
    ("UnsupportedOperation.SpecialInstanceType", {"InstanceId": "ins-special"}),
    ("UnsupportedOperation.StoppedModeStopCharging", {"InstanceId": "ins-stopped-free"}),
    ("UnsupportedOperation.StoppedModeStopChargingSameFamily", {"InstanceId": "ins-stopped-same"}),
    ("UnsupportedOperation.SystemDiskType", {"InstanceId": "ins-123456", "SystemDisk": {"DiskType": "INVALID_TYPE"}}),
    ("UnsupportedOperation.UnsupportedARMChangeInstanceFamily", {"InstanceId": "ins-arm", "InstanceType": "non-arm"}),
    ("UnsupportedOperation.UnsupportedChangeInstanceFamily",
     {"InstanceId": "ins-source", "InstanceType": "target-family"}),
    ("UnsupportedOperation.UnsupportedChangeInstanceFamilyToARM",
     {"InstanceId": "ins-non-arm", "InstanceType": "arm-type"}),
    ("UnsupportedOperation.UnsupportedChangeInstanceToThisInstanceFamily",
     {"InstanceId": "ins-current", "InstanceType": "unsupported-target"}),
]


class TestModifyInstancesConfig:
    @patch('requests.post')
    def test_success_case(self, mock_post):
        """测试成功场景"""
        mock_post.return_value.json.return_value = {
            "Response": {"RequestId": "success-123"}
        }
        params = {"InstanceId": "ins-valid", "InstanceType": "S2.SMALL1"}
        result = send_request("ModifyInstancesConfig", params)
        assert "RequestId" in result["Response"]

    @patch('requests.post')
    def test_all_error_codes(self, mock_post, error_code, params):
        """参数化测试所有错误码"""
        # 构造错误响应
        mock_response = MagicMock()
        mock_response.json.return_value = {
            "Response": {
                "Error": {
                    "Code": error_code,
                    "Message": f"Test for {error_code}"
                },
                "RequestId": "error-123"
            }
        }
        mock_post.return_value = mock_response

        # 发送请求
        result = send_request("ModifyInstancesConfig", params)

        # 验证错误码
        assert result["Response"]["Error"]["Code"] == error_code, f"Error code {error_code} verification failed"


# 生成参数化测试用例
@pytest.mark.parametrize("error_code, params", ERROR_CODE_CASES)
def test_parametrized_errors(error_code, params):
    # 由于pytest的限制，需要将测试逻辑放在函数内
    with patch('requests.post') as mock_post:
        mock_response = MagicMock()
        mock_response.json.return_value = {
            "Response": {
                "Error": {"Code": error_code},
                "RequestId": "test-request"
            }
        }
        mock_post.return_value = mock_response

        send_request("ModifyInstancesConfig", params)
        assert mock_post.called, f"Request not made for {error_code}"
        response = mock_post.return_value.json()
        assert response["Response"]["Error"]["Code"] == error_code


# 启动测试函数
def run_tests():
    pytest.main([__file__, "-v", "-s", "--cov=test_modify_instance_config"])


if __name__ == "__main__":
    run_tests()